#include "mon_cfg.h"

#define PA_SDA    PORTBbits.RB5
#define PA_SCL    PORTBbits.RB4
#define PA_SDA_DIR    TRISBbits.TRISB5
#define PA_SCL_DIR    TRISBbits.TRISB4
#define PB_SDA    PORTBbits.RB3
#define PB_SCL    PORTBbits.RB2
#define PB_SDA_DIR    TRISBbits.TRISB3
#define PB_SCL_DIR    TRISBbits.TRISB2
#define PC_SDA    PORTBbits.RB1
#define PC_SCL    PORTBbits.RB0
#define PC_SDA_DIR    TRISBbits.TRISB1
#define PC_SCL_DIR    TRISBbits.TRISB0

I2C_Device dev_a;
I2C_Device dev_b;
I2C_Device dev_c;

static void I2CMasterMon_SetIOValue(I2C_Channel channel, unsigned char iosel, unsigned char Value)
{
    switch(channel)
    {
        case I2C_CHANNEL_A:
            if(iosel == SDA)
            {
                PA_SDA = Value;
            }
            else
            {
                PA_SCL = Value;
            }
            break;
        case I2C_CHANNEL_B:
            if(iosel == SDA)
            {
                PB_SDA = Value;
            }
            else
            {
                PB_SCL = Value;
            }
            break;
        case I2C_CHANNEL_C:
            if(iosel == SDA)
            {
                PC_SDA = Value;
            }
            else
            {
                PC_SCL = Value;
            }
            break;
        case I2C_CHANNEL_D:
        default:break;
    }
}

static unsigned char I2CMasterMon_GetIOValue(I2C_Channel channel, unsigned char iosel)
{
    unsigned char ret = 0;
    switch(channel)
    {
        case I2C_CHANNEL_A:
            if(iosel == SDA)
            {
                ret = PA_SDA;
            }
            else
            {
                ret = PA_SCL;
            }
            break;
        case I2C_CHANNEL_B:
            if(iosel == SDA)
            {
                ret = PB_SDA;
            }
            else
            {
                ret = PB_SCL;
            }
            break;
        case I2C_CHANNEL_C:
            if(iosel == SDA)
            {
                ret = PC_SDA;
            }
            else
            {
                ret = PC_SCL;
            }
            break;
        case I2C_CHANNEL_D:
        default:ret |=0x80;break;
    }
    return ret;
}

static void I2CMasterMon_SetIODir(I2C_Channel channel, unsigned char iosel, unsigned char dir)
{
    switch(channel)
    {
        case I2C_CHANNEL_A:
            if(iosel == SDA)
            {
                PA_SDA_DIR = dir;
            }
            else
            {
                PA_SCL_DIR = dir;
            }
            break;
        case I2C_CHANNEL_B:
            if(iosel == SDA)
            {
                PB_SDA_DIR = dir;
            }
            else
            {
                PB_SCL_DIR = dir;
            }
            break;
        case I2C_CHANNEL_C:
            if(iosel == SDA)
            {
                PC_SDA_DIR = dir;
            }
            else
            {
                PC_SCL_DIR = dir;
            }
            break;
        case I2C_CHANNEL_D:
        default:break;
    }
}

static void I2CMasterMon_InitIO(I2C_Device dev)
{
	I2CMasterMon_SetIODir(dev.channel,SDA,IO_OUTPUT);
	I2CMasterMon_SetIODir(dev.channel,SCL,IO_OUTPUT);
	I2CMasterMon_SetIOValue(dev.channel,SDA,HIGH);
	I2CMasterMon_SetIOValue(dev.channel,SCL,HIGH);
}

void I2CMasterMon_Init(void)
{
    dev_a.channel = I2C_CHANNEL_A;
    dev_a.stat = I2C_STATUS_Success;
//    dev_a.delay = I2C_MON_DELAY_US;
//    dev_a.noack_timeout_count = I2C_MON_NOACK_COUNT;
    I2CMasterMon_InitIO(dev_a);

    dev_b.channel = I2C_CHANNEL_B;
    dev_b.stat = I2C_STATUS_Success;
 //   dev_b.delay = I2C_MON_DELAY_US;
 //   dev_b.noack_timeout_count = I2C_MON_NOACK_COUNT;
    I2CMasterMon_InitIO(dev_b);

    dev_c.channel = I2C_CHANNEL_C;
    dev_c.stat = I2C_STATUS_Success;
//    dev_c.delay = I2C_MON_DELAY_US;
//    dev_c.noack_timeout_count = I2C_MON_NOACK_COUNT;
    I2CMasterMon_InitIO(dev_c);
}

static void I2CMasterMon_Start(I2C_Channel channel)
{
    I2CMasterMon_SetIODir(channel,SDA,IO_OUTPUT);
    I2CMasterMon_SetIODir(channel,SCL,IO_OUTPUT);
    __delay_us(I2C_MON_DELAY_US);
    I2CMasterMon_SetIOValue(channel,SDA,HIGH);
    I2CMasterMon_SetIOValue(channel,SCL,HIGH);
    __delay_us(I2C_MON_DELAY_US);
    I2CMasterMon_SetIOValue(channel,SDA,LOW);
    __delay_us(I2C_MON_DELAY_US);
    I2CMasterMon_SetIOValue(channel,SCL,LOW);
}

static void I2CMasterMon_Stop(I2C_Channel channel)
{
    __delay_us(I2C_MON_DELAY_US);
    I2CMasterMon_SetIODir(channel,SDA,IO_OUTPUT);
    I2CMasterMon_SetIODir(channel,SCL,IO_OUTPUT);
    __delay_us(I2C_MON_DELAY_US);
    I2CMasterMon_SetIOValue(channel,SCL,LOW);
    __delay_us(I2C_MON_DELAY_US);
    I2CMasterMon_SetIOValue(channel,SDA,LOW);
    __delay_us(I2C_MON_DELAY_US);
    I2CMasterMon_SetIOValue(channel,SCL,HIGH);
    __delay_us(I2C_MON_DELAY_US);
    I2CMasterMon_SetIOValue(channel,SDA,HIGH);
    __delay_us(I2C_MON_DELAY_US);
}

void I2CMasterMon_TXOneByte(I2C_Device dev, unsigned char data )
{
    unsigned char temp = 8, err_count = 0;
    while(temp --)
    {
        I2CMasterMon_SetIODir(dev.channel,SDA,IO_OUTPUT);
        I2CMasterMon_SetIODir(dev.channel,SCL,IO_OUTPUT);
        __delay_us(I2C_MON_DELAY_US);
        if((data&0b10000000))
        {
            I2CMasterMon_SetIOValue(dev.channel,SDA,HIGH);
        }
        else
        {
            I2CMasterMon_SetIOValue(dev.channel,SDA,LOW);
        }
        I2CMasterMon_SetIOValue(dev.channel,SCL,HIGH);
        __delay_us(I2C_MON_DELAY_US);
        I2CMasterMon_SetIOValue(dev.channel,SCL,LOW);
        data <<= 1;
    }
    I2CMasterMon_SetIODir(dev.channel,SDA,IO_INPUT);
    I2CMasterMon_SetIOValue(dev.channel,SCL,HIGH);
    while(I2CMasterMon_GetIOValue(dev.channel,SDA))
    {
        __delay_us(I2C_MON_DELAY_US);
        I2CMasterMon_SetIOValue(dev.channel,SCL,LOW);
        __delay_us(I2C_MON_DELAY_US);
        I2CMasterMon_SetIOValue(dev.channel,SCL,HIGH);
        __delay_us(I2C_MON_DELAY_US);
        err_count ++;
        if(err_count >I2C_MON_NOACK_COUNT)
        {
            dev.stat = I2C_STATUS_NoAck;
            break;
        }   
    }
    I2CMasterMon_SetIOValue(dev.channel,SCL,LOW);
}

void I2CMasterMon_RXOneByte(I2C_Device dev, unsigned char* pdata, unsigned char ack)
{
    unsigned char temp = 8, buf = 0;
    I2CMasterMon_SetIODir(dev.channel,SDA,IO_INPUT);
    while(temp --)
    {
        __delay_us(I2C_MON_DELAY_US);
        I2CMasterMon_SetIOValue(dev.channel,SCL,HIGH);
        buf = (buf<<1)|I2CMasterMon_GetIOValue(dev.channel,SDA);
        I2CMasterMon_SetIOValue(dev.channel,SCL,LOW);
    }
    *pdata = buf;
    if(ack == NOACK)
	{
        __delay_us(I2C_MON_DELAY_US);
        I2CMasterMon_SetIODir(dev.channel,SDA,IO_OUTPUT);
        I2CMasterMon_SetIODir(dev.channel,SCL,IO_OUTPUT);
        __delay_us(I2C_MON_DELAY_US);
        I2CMasterMon_SetIOValue(dev.channel,SDA,HIGH);
        __delay_us(I2C_MON_DELAY_US);
        I2CMasterMon_SetIOValue(dev.channel,SCL,HIGH);
        __delay_us(I2C_MON_DELAY_US);
        I2CMasterMon_SetIOValue(dev.channel,SCL,LOW);
    }
    else
    {
        __delay_us(I2C_MON_DELAY_US);
        I2CMasterMon_SetIODir(dev.channel,SDA,IO_OUTPUT);
        I2CMasterMon_SetIODir(dev.channel,SCL,IO_OUTPUT);
        __delay_us(I2C_MON_DELAY_US);
        I2CMasterMon_SetIOValue(dev.channel,SDA,LOW);
        __delay_us(I2C_MON_DELAY_US);
        I2CMasterMon_SetIOValue(dev.channel,SCL,HIGH);
        __delay_us(I2C_MON_DELAY_US);
        I2CMasterMon_SetIOValue(dev.channel,SCL,LOW);
    }
}

void I2C_master_rw_synchronous(I2C_Device dev, unsigned char addr, unsigned char *pdata, unsigned char length, I2C_Mode mode)
{
    unsigned char i;
    if(!(mode&I2C_MODE_SkipStart))
    {
        I2CMasterMon_Start(dev.channel);
    }
    if(addr&0x01)//read
    {
        I2CMasterMon_TXOneByte(dev, addr );
        if(dev.stat != I2C_STATUS_Success)
        {
            I2CMasterMon_Stop(dev.channel);
            return;
        }
        for(i=0;i<length;i++)
        {
            if((i==(length-1))&&!(mode&I2C_MODE_SkipStart))
            {
                I2CMasterMon_RXOneByte(dev, pdata+i, NOACK);
            }
            else
            {
                I2CMasterMon_RXOneByte(dev, pdata+i, ACK);
            }
            if(dev.stat != I2C_STATUS_Success) break;
        }
    }
    else
    {
        if(!(mode&I2C_MODE_SkipStart))
        {
            I2CMasterMon_TXOneByte(dev, addr );
            if(dev.stat != I2C_STATUS_Success)
            {
                I2CMasterMon_Stop(dev.channel);
                return;
            }
        }
        for(i=0;i<length;i++)
        {
            I2CMasterMon_TXOneByte(dev, pdata[i] );
            if(dev.stat != I2C_STATUS_Success)
            {
                I2CMasterMon_Stop(dev.channel);
                break;
            }    
        }
    }
    if(!(mode&I2C_MODE_SkipStop))
    {
        I2CMasterMon_Stop(dev.channel);
    }
}


